/* 
 * Copyright 2010 Ziya Guven Koylu, Ozge Koylu
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.koylu.caffein;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.digester.Digester;

import com.koylu.caffein.exception.CaffeinConfigException;
import com.koylu.caffein.model.caffein.CaffeinConfig;
import com.koylu.caffein.model.caffein.CaffeinConfigProperty;


public class CaffeinFactory {

	private static Digester caffeinConfigDigester;
	private static Map<String, CaffeinConfig> caffeinConfigMap = new HashMap<String, CaffeinConfig>();

	static {
		caffeinConfigDigester = new Digester();
		caffeinConfigDigester.addObjectCreate("*/caffein", CaffeinConfig.class);
		caffeinConfigDigester.addSetProperties("*/caffein", "class", "caffeinClass");
		caffeinConfigDigester.addSetProperties("*/caffein", "scope", "caffeinScope");
		caffeinConfigDigester.addSetProperties("*/caffein", "enableQueryLogging", "enableQueryLogging");

		caffeinConfigDigester.addObjectCreate("*/datasource", CaffeinConfigProperty.class);
		caffeinConfigDigester.addSetProperties("*/datasource", "class", "clazz");
		caffeinConfigDigester.addSetNext("*/datasource", "setDataSource");
		
		caffeinConfigDigester.addObjectCreate("*/cache", CaffeinConfigProperty.class);
		caffeinConfigDigester.addSetProperties("*/cache", "class", "clazz");
		caffeinConfigDigester.addSetNext("*/cache", "setCacheManager");
		
		caffeinConfigDigester.addObjectCreate("*/lock", CaffeinConfigProperty.class);
		caffeinConfigDigester.addSetProperties("*/lock", "class", "clazz");
		caffeinConfigDigester.addSetNext("*/lock", "setLockManager");

		caffeinConfigDigester.addObjectCreate("*/property", CaffeinConfigProperty.class);
		caffeinConfigDigester.addSetProperties("*/property", "name", "name");
		caffeinConfigDigester.addBeanPropertySetter("*/property", "value");
		caffeinConfigDigester.addSetNext("*/property", "addChild");

		caffeinConfigDigester.addObjectCreate("*/query", CaffeinConfigProperty.class);
		caffeinConfigDigester.addSetProperties("*/query", "class", "clazz");
		caffeinConfigDigester.addSetNext("*/query", "setQuery");

		caffeinConfigDigester.addObjectCreate("*/clazz-list", ArrayList.class);
		caffeinConfigDigester.addSetNext("*/clazz-list", "setClazzList");

		caffeinConfigDigester.addObjectCreate("*/clazz", CaffeinConfigProperty.class);
		caffeinConfigDigester.addSetProperties("*/clazz", "name", "name");
		caffeinConfigDigester.addSetNext("*/clazz", "add");
		
		caffeinConfigDigester.addObjectCreate("*/proc-list", ArrayList.class);
		caffeinConfigDigester.addSetNext("*/proc-list", "setProcList");
		
		caffeinConfigDigester.addObjectCreate("*/proc", CaffeinConfigProperty.class);
		caffeinConfigDigester.addSetProperties("*/proc", "name", "name");
		caffeinConfigDigester.addSetNext("*/proc", "add");
	}
	
	public static synchronized CaffeinConfig getCaffeinConfig(String file) throws Exception {
		CaffeinConfig caffeinConfig = caffeinConfigMap.get(file);
		if (caffeinConfig == null) {
			caffeinConfig = (CaffeinConfig) fileToObject(caffeinConfigDigester, file);
			if(caffeinConfig == null){
				throw new CaffeinConfigException("invalid caffein file:"+file);
			}
			caffeinConfigMap.put(file, caffeinConfig);
		}
		return caffeinConfig;
	}

	public static synchronized Caffein getCaffein(String file) throws Exception {
		CaffeinConfig caffeinConfig = caffeinConfigMap.get(file);
		if (caffeinConfig == null) {
			caffeinConfig = (CaffeinConfig) fileToObject(caffeinConfigDigester, file);
			if(caffeinConfig == null){
				throw new CaffeinConfigException("invalid caffein file:"+file);
			}
			caffeinConfigMap.put(file, caffeinConfig);
		}
		return caffeinConfig.getCaffein();
	}

	public static Object fileToObject(Digester digester, String file) throws Exception {
		if (!file.startsWith("/")) {
			file = "/" + file;
		}
		InputStream inputStream = CaffeinFactory.class.getResourceAsStream(file);
		if(inputStream == null){
			return null;
		}
		return digester.parse(inputStream);
	}
	
	public synchronized static void clear(){
		caffeinConfigMap.clear();
	}
}